import chalk from 'chalk';
import {CollUtil} from '../../../utils/CollUtil.js';
import {DateUtil} from '../../../utils/DateUtil.js';
import {InfoConsoleTable} from '../../../utils/InfoConsoleTable.js';
import {StrUtil} from '../../../utils/StrUtil.js';
import {AppUtil} from '../../../utils/AppUtil.js';
import {getProjectOpsFile} from '../../../utils/OpsFile.js';

export const infoMixin = {
    getEnvironmentName(envKey) {
        const envMap = {
            'f': 'feature',
            'feature': 'feature',
            't': 'feature',
            'ft': 'feature',
            'u': 'uat',
            'uat': 'uat',
            'b': 'beta',
            'p': 'prod',
            'prod': 'prod'
        };
        return envMap[envKey] || envKey;
    },

    async getFlowBasicInfoLines(envKey) {
        if (!this.projectOpsFile) {
            return Array.from(accounts)
                .map(account => account.trim())
                .filter(account => account)
                .map(account => account.includes('@') ? account : `${account}@hstong.com`);
        }
        const [flowUrl, flowName] = await Promise.all([
            this.projectOpsFile.read('flow.url'),
            this.projectOpsFile.read('flow.ops_flow_name')
        ]);
        const normalizedEnv = typeof envKey === 'string' && envKey.trim() ? envKey : 'feature';
        const envLabel = this.buildEnvMap[normalizedEnv] || normalizedEnv;
        const urlText = flowUrl || '未配置';
        const nameText = flowName || '未配置';
        return [
            `发布单地址: ${urlText}`,
            `发布单名称: ${nameText}`,
            `部署环境: ${normalizedEnv} - ${envLabel}`
        ];
    },

    async displayEnvironmentInfo(appNames = [], environment) {
        const flowIdRaw = await this.projectOpsFile.read('flow.id');
        const flowTypeRaw = await this.projectOpsFile.read('flow.flow_type');
        const flowId = flowIdRaw ? String(flowIdRaw).trim() : '';
        const flowType = flowTypeRaw ? String(flowTypeRaw).trim() : '';
        if (StrUtil.isNull(flowId) || StrUtil.isNull(flowType)) {
            throw new Error('发布单信息缺失，请先执行 nb init 初始化项目');
        }

        const appAndBranch = await this.opsClient.getAppAndBranch(flowId, flowType);
        if (CollUtil.isEmptyArray(appAndBranch)) {
            throw new Error('发布单未配置任何应用，请检查 ops.conf');
        }

        const requestedNames = new Set(
            (appNames || [])
                .map(name => String(name).trim())
                .filter(Boolean)
        );
        const needFilter = requestedNames.size > 0;

        const targets = appAndBranch
            .filter(item => item && item.app)
            .map(item => ({
                appName: item.app,
                branch: item.name || '',
                pluginList: Array.isArray(item.plugin_list) ? item.plugin_list : []
            }))
            .filter(item => {
                if (!needFilter) {
                    return true;
                }
                if (requestedNames.has(item.appName)) {
                    return true;
                }
                return item.pluginList.some(plugin => requestedNames.has(plugin?.app));
            });

        if (CollUtil.isEmptyArray(targets)) {
            throw new Error('未匹配到任何应用，请检查参数是否正确');
        }

        const flowInfoLines = await this.getFlowBasicInfoLines(environment);
        const introLines = [
            '',
            chalk.cyan('🌍 发布单环境检测'),
            ...flowInfoLines.map(line => `  ${line}`),
            ''
        ];
        for (const line of introLines) {
            console.log(line);
        }

        const table = new InfoConsoleTable('普通发布');
        table.printHeader();

        for (const target of targets) {
            const type = target.pluginList.length > 0 ? 'jz' : 'app';
            table.addRow({
                type,
                name: target.appName,
                buildStatus: 'wait',
                buildDesc: '查询中…',
                sonarStatus: 'wait',
                sonarDesc: '',
                deployStatus: 'wait',
                deployDesc: '',
                runStatus: 'wait',
                runDesc: '',
                time: DateUtil.nowTime(),
                desc: '',
                opsUrl: ''
            });

            if (target.pluginList.length > 0) {
                for (const plugin of target.pluginList) {
                    if (!plugin?.app) {
                        continue;
                    }
                    table.addRow({
                        type: 'plugin',
                        name: plugin.app,
                        buildStatus: 'wait',
                        buildDesc: '等待基座检测…',
                        sonarStatus: 'un',
                        sonarDesc: '',
                        deployStatus: 'un',
                        deployDesc: '',
                        runStatus: 'un',
                        runDesc: '',
                        time: DateUtil.nowTime(),
                        desc: '',
                        opsUrl: ''
                    });
                }
            }

            try {
                const {rowUpdate, pluginUpdates} = await this.inspectAppEnvironment({
                    appName: target.appName,
                    environment,
                    flowId,
                    expectedBranch: target.branch,
                    pluginList: target.pluginList
                });
                table.updateRow(rowUpdate);
                for (const pluginUpdate of pluginUpdates) {
                    table.updateRow(pluginUpdate);
                }
            } catch (error) {
                this.logger.warn(`检测 ${target.appName} 环境失败: ${error.message}`);
                table.updateRow({
                    name: target.appName,
                    buildStatus: 'error',
                    buildDesc: '',
                    sonarStatus: 'un',
                    sonarDesc: '',
                    deployStatus: 'un',
                    deployDesc: '',
                    runStatus: 'error',
                    runDesc: error.message,
                    time: DateUtil.nowTime(),
                    desc: ''
                });
                if (target.pluginList.length > 0) {
                    for (const plugin of target.pluginList) {
                        if (!plugin?.app) {
                            continue;
                        }
                        table.updateRow({
                            name: plugin.app,
                            buildStatus: 'error',
                            buildDesc: '基座检测失败',
                            sonarStatus: 'un',
                            sonarDesc: '',
                            deployStatus: 'un',
                            deployDesc: '',
                            runStatus: 'un',
                            runDesc: '',
                            time: DateUtil.nowTime(),
                            desc: ''
                        });
                    }
                }
            }
        }
        table.moveCursorToBottom();
        console.log();
    },

    async inspectAppEnvironment({appName, environment, flowId, expectedBranch, pluginList = []}) {
        const {podEnvData, envCount, imageInfo, imageKey} =
            await this.fetchPodAndImage(appName, environment, flowId);

        const appStatus = podEnvData?.status?.app_status || {};
        const restart = Number(appStatus.restart || 0);
        const ready = Number(appStatus.ready || 0);
        const total = Number(appStatus.total || 0);
        const phase = podEnvData?.status?.phase || '';
        const creationTimestamp = podEnvData?.metadata?.creation_timestamp || '';

        let runStatus = 'running';
        let runDesc = phase || '运行中';
        if (restart > 0 && ready!==total) {
            runStatus = 'error';
            runDesc = `已重启${restart}次`;
        } else if (total === 0) {
            runStatus = 'wait';
            runDesc = '未发现实例';
        } else if (ready < total) {
            runStatus = 'wait';
            runDesc = `启动中 ${ready}/${total}`;
        }

        const imageBranch = imageInfo?.br || '';
        const buildTime = this.formatCreationTime(creationTimestamp);
        let buildStatus = 'success';
        let buildDesc = '';
        if (expectedBranch && imageBranch && expectedBranch !== imageBranch) {
            buildStatus = 'warn';
            buildDesc = `分支 ${imageBranch} ≠ 发布单${expectedBranch}`;
        } else if (!imageBranch) {
            buildStatus = 'warn';
            buildDesc = expectedBranch ? `目标分支 ${expectedBranch}` : '未获取分支信息';
        } else {
            buildDesc = `分支 ${imageBranch}`;
        }

        let deployStatus = 'success';
        let deployDesc = envCount > 1 ? `实例数 ${envCount}` : '实例正常';
        if (runStatus === 'error') {
            deployStatus = 'error';
            deployDesc = '实例异常';
        } else if (runStatus === 'wait') {
            deployStatus = 'wait';
            deployDesc = runDesc;
        }

        const imageSubject = StrUtil.getLastDescription(imageInfo?.subject)?.trim();
        const baseDescParts = [];
        if (imageSubject) {
            baseDescParts.push(imageSubject);
        }

        const pluginUpdates = [];
        if (CollUtil.notEmptyArray(pluginList)) {
            const pluginInfoList = Array.isArray(imageInfo?.koupleless_plugins) ? imageInfo.koupleless_plugins : [];
            const pluginInfoMap = new Map();
            for (const pluginInfo of pluginInfoList) {
                if (pluginInfo?.name) {
                    pluginInfoMap.set(pluginInfo.name, pluginInfo);
                }
            }

            for (const plugin of pluginList) {
                const pluginName = plugin?.app;
                if (!pluginName) {
                    continue;
                }
                const expectedPluginBranch = plugin?.name || '';
                const pluginImageInfo = pluginInfoMap.get(pluginName);
                let pluginBuildStatus = 'warn';
                let pluginBuildDesc = '镜像缺少该插件';
                if (pluginImageInfo) {
                    pluginBuildStatus = 'success';
                    const actualBranch = pluginImageInfo.branch || '';
                    if (expectedPluginBranch && actualBranch && expectedPluginBranch !== actualBranch) {
                        pluginBuildStatus = 'warn';
                        pluginBuildDesc = `环境 ${actualBranch} ≠ 发布单 ${expectedPluginBranch}`;
                    } else {
                        pluginBuildDesc = actualBranch ? `分支 ${actualBranch}` : '未获取分支';
                    }
                    const pluginRev = pluginImageInfo.rev ? String(pluginImageInfo.rev).slice(0, 7) : '';
                    if (pluginRev) {
                        pluginBuildDesc += ` rev ${pluginRev}`;
                    }
                }
                const pluginRevDesc = this.formatPluginDesc(pluginImageInfo?.revDesc);
                pluginUpdates.push({
                    name: pluginName,
                    buildStatus: pluginBuildStatus,
                    buildDesc: pluginBuildDesc,
                    sonarStatus: 'un',
                    sonarDesc: '',
                    deployStatus: 'un',
                    deployDesc: '',
                    runStatus: 'un',
                    runDesc: '',
                    desc: pluginRevDesc,
                    time: buildTime,
                    opsUrl: ''
                });
            }
        }

        return {
            rowUpdate: {
                name: appName,
                buildStatus,
                buildDesc,
                sonarStatus: 'un',
                sonarDesc: '',
                deployStatus,
                deployDesc,
                runStatus,
                runDesc,
                desc: baseDescParts.join(' | '),
                time: buildTime,
                opsUrl: ''
            },
            pluginUpdates
        };
    },

    async fetchPodAndImage(appName, environment, flowId) {
        const environmentName = this.getEnvironmentName(environment);
        const {matchedKey} = await this.getServerNodeEnv(appName, environment);
        if (StrUtil.isNull(matchedKey)) {
            throw new Error(`${appName} 缺少 ${environment} 环境配置`);
        }

        const envData = await this.opsClient.podV2(appName, matchedKey);
        if (!envData || Object.keys(envData).length === 0) {
            throw new Error(`${matchedKey} 环境未发现实例`);
        }
        let envCount = 0;
        let podEnvData = null;
        for (const key of Object.keys(envData)) {
            envCount++;
            const current = envData[key];
            if (environmentName === 'feature') {
                if (environment === 'ft' && current?.attached?.version?.rid) {
                    if (String(current.attached.version.rid) === String(flowId)) {
                        podEnvData = current;
                        break;
                    }
                } else if ((environment === 'feature' || environment === 'f') && !current?.attached?.version) {
                    podEnvData = current;
                    break;
                }
            }
            podEnvData = current;
        }

        if (!podEnvData || StrUtil.isEmptyObject(podEnvData)) {
            throw new Error(`${matchedKey} 环境未找到可用服务`);
        }

        const image = podEnvData?.status?.app_status?.image || '';
        const imageKey = StrUtil.getLastPath(image);
        let imageInfo = null;
        if (StrUtil.notNull(imageKey)) {
            try {
                imageInfo = await this.opsClient.imageVersion(appName, imageKey);
            } catch (error) {
                this.logger.warn(`获取 ${appName} 镜像信息失败: ${error.message}`);
            }
        }

        return {
            matchedKey,
            podEnvData,
            envCount,
            imageInfo,
            imageKey
        };
    },

    formatCreationTime(timestamp) {
        if (!timestamp || typeof timestamp !== 'string') {
            return DateUtil.nowTime();
        }
        if (timestamp.includes('T')) {
            const parsed = DateUtil.parseToTimeV2(timestamp);
            return parsed || timestamp;
        }
        if (timestamp.includes(' ')) {
            const parsed = DateUtil.parseToTime(timestamp);
            return parsed || timestamp;
        }
        return timestamp;
    },

    formatPluginDesc(revDesc, limit = 120) {
        if (!revDesc) {
            return '';
        }
        const singleLine = String(revDesc).replace(/\s+/g, ' ').trim();
        if (singleLine.length <= limit) {
            return singleLine;
        }
        return `${singleLine.slice(0, limit - 3)}...`;
    },

    async handleDeleteCommand() {
        this.logger.step(1, '删除当前发布单的所有项目');
        this.logger.warn('此操作将删除当前发布单的所有项目');

        // TODO: 实现删除逻辑
        // 1. 确认当前目录是否为发布单项目
        // 2. 列出将要删除的项目
        // 3. 用户确认
        // 4. 执行删除操作

        this.logger.info('删除操作完成');
    },

    async handleInfoCommand(options = {}) {
        this.logger.info(
            `指令 options=${JSON.stringify(options)} `
        );
        this.assignProjectOpsFile(getProjectOpsFile());
        await this.initClient();

        // 检查是否有环境参数
        if (options.feature) {
            await this.displayEnvironmentInfo(StrUtil.parseAppArgs(options.feature), 'feature');
            return;
        }
        if (options.ft) {
            await this.displayEnvironmentInfo(StrUtil.parseAppArgs(options.ft), 'ft');
            return;
        }
        if (options.uat) {
            await this.displayEnvironmentInfo(StrUtil.parseAppArgs(options.uat), 'uat');
            return;
        }
        if (options.beta) {
            await this.displayEnvironmentInfo(StrUtil.parseAppArgs(options.beta), 'beta');
            return;
        }
        if (options.prod) {
            await this.displayEnvironmentInfo(StrUtil.parseAppArgs(options.prod), 'prod');
            return;
        }
        throw new Error("不支持的环境");
    },

    async handleJumpCommand(options = {}) {
        const resolvedOptions = typeof options?.opts === 'function' ? options.opts() : options;
        const support = Boolean(resolvedOptions?.support);
        const plan = Boolean(resolvedOptions?.plan);
        if (support && plan && ops) {
            throw new Error('请勿同时使用 --support 与 --plan 与 --ops 参数');
        }
        if (!this.projectOpsFile) {
            this.assignProjectOpsFile(getProjectOpsFile());
        }
        const targetConfig = support ? {
            key: 'support.url',
            label: '依赖发布单'
        } : plan ? {
            key: 'plan.url',
            label: '发布计划'
        } : {
            key: 'flow.url',
            label: '发布单'
        };
        this.logger.step(1, `跳转打开${targetConfig.label}网页`);
        const targetUrl = this.projectOpsFile.read(targetConfig.key);
        if (StrUtil.isNull(targetUrl)) {
            throw new Error(`${targetConfig.label}地址未配置，请在发布单目录执行 nb init 完成初始化`);
        }
        this.logger.info(`正在打开${targetConfig.label}链接: ${targetUrl}`);
        try {
            await AppUtil.openUrl(targetUrl);
            this.logger.success(`${targetConfig.label}网页已打开`);
        } catch (error) {
            this.logger.error(`${targetConfig.label}网页打开失败: ${error.message}`);
            throw error;
        }
    },
};
